#include "login.h"
#include "ui_login.h"
//单例模式
#include "common/logininfoinstance.h"
//加密解密
#include "common/des.h"
#include <qDebug>
#include <QPainter>
#include <QRegExp>
#include <QRegularExpression>
#include <QMessageBox>
//发送HTTP信息以及接收服务器相应
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
//json所需头文件
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>

login::login(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::login)
{
    ui->setupUi(this);

    // 网络请求（http）类
    m_manager = Common::getNetManager();
    // 此处无需指定父窗口
    m_mainWin = new MainWindow;

    //设置标题栏隐藏
    this->setWindowFlag(Qt::FramelessWindowHint);

    ui->titlebar->setmyParent(this);

    ui->stackedWidget->setCurrentIndex(0);

    //
    connect(ui->titlebar,&mytitlebar::showSetWindow,[=]()
    {
        ui->stackedWidget->setCurrentIndex(2);
    });
    connect(ui->titlebar,&mytitlebar::showMinWindow,[=]()
    {
        this->showMinimized();
    });
    connect(ui->titlebar,&mytitlebar::closeMyWindow,[=]()
    {
        //有不同情况，设置页或者注册页，会返回到登录页
        if(ui->stackedWidget->currentIndex() == 1)
        {
            ui->stackedWidget->setCurrentIndex(0);
            //清空内容
        }
        else if(ui->stackedWidget->currentIndex() == 2)
        {
            ui->stackedWidget->setCurrentIndex(0);
            //清空内容
        }
        //如果是登录页，则关闭
        else
        {
            this->close();
        }
    });

    //从主窗口切换回登录页,主窗口隐藏，此窗口显示
    connect(m_mainWin,&MainWindow::changeUser,[=]()
    {
        qDebug()<<"从主窗口切换回登录页,主窗口隐藏，此窗口显示";
        m_mainWin->hide();
        this->show();
    });

    readCfg();
}

login::~login()
{
    delete ui;
}

QByteArray login::setLoginJson(QString user, QString pwd)
{
    QMap<QString,QVariant> login;
    login.insert("user",user);
    login.insert("pwd",pwd);
    //
    QJsonDocument jsonDocument = QJsonDocument::fromVariant(login);
    if(jsonDocument.isNull())
    {
        //如果为空则返回空字符串
        return "";
    }
    return jsonDocument.toJson();
}

QByteArray login::setRegisterJson(QString userName, QString nickName, QString firstPwd, QString phone, QString email)
{
    QMap<QString,QVariant> reg;
    reg.insert("userName",userName);
    reg.insert("nickName",nickName);
    reg.insert("firstPwd",firstPwd);
    reg.insert("phone",phone);
    reg.insert("email",email);
    //
    QJsonDocument jsonDocument = QJsonDocument::fromVariant(reg);
    //如果为空则返回一个空字符串
    if(jsonDocument.isNull())
    {
        return "";
    }
    return jsonDocument.toJson();
}

// 得到服务器回复的登陆状态， 状态码返回值为 "000", 或 "001"，还有登陆section
QStringList login::getLoginStatus(QByteArray json)
{
    //这地方直接复制的
    QJsonParseError error;
    QStringList list;

    // 将来源数据json转化为JsonDocument
    // 由QByteArray对象构造一个QJsonDocument对象，用于我们的读写操作
    QJsonDocument doc = QJsonDocument::fromJson(json, &error);
    if (error.error == QJsonParseError::NoError)
    {
        if (doc.isNull() || doc.isEmpty())
        {
            cout << "doc.isNull() || doc.isEmpty()";
            return list;
        }

        if( doc.isObject() )
        {
            //取得最外层这个大对象
            QJsonObject obj = doc.object();
            cout << "服务器返回的数据" << obj;
            //状态码
            list.append( obj.value( "code" ).toString() );
            //登陆token
            list.append( obj.value( "token" ).toString() );
        }
    }
    else
    {
        cout << "err = " << error.errorString();
    }

    return list;
}
//添加背景图片
void login::paintEvent(QPaintEvent *event)
{
    //
    QPainter p(this);
    p.drawPixmap(0,0,this->width(),this->height(),QPixmap(":/images/login_bk.jpg"));
}

//注册按键点击函数
void login::on_tologinBtn_clicked()
{
    //取出数据
    QString username = ui->reg_usrname->text();
    QString nickname = ui->reg_nickname->text();
    QString passwd = ui->reg_password->text();
    QString confirmPwd = ui->reg_surepassword->text();
    QString email = ui->reg_mail->text();
    QString phone = ui->reg_tel->text();

    //对数据使用正则表达式进行校验
    if(true)
    {
    //设置第一种校验，正则规则来自于common文件夹下common.h
    //QString USER = "^[a-zA-Z\\d_@#-*]{3,16}$";
    QRegExp regepx(USER_REG);//"^[a-zA-Z\\d_@#-\\*]\\{3,16\\}$"
    //校验用户名
    if(!regepx.exactMatch(username))
    {
        //qDebug()<<username;
        //加了！代表如果匹配失败，返回值为假，if判断就会为真，执行括号内语句
        QMessageBox::warning(this,"警告","用户名格式不正确");
        //清空内容
        ui->reg_usrname->clear();
        //设置焦点,编辑此文本框
        ui->reg_usrname->setFocus();
        return;
    }
    //校验昵称
    if(!regepx.exactMatch(nickname))
    {
        //qDebug()<<username;
        //加了！代表如果匹配失败，返回值为假，if判断就会为真，执行括号内语句
        QMessageBox::warning(this,"警告","昵称格式不正确");
        //清空内容
        ui->reg_nickname->clear();
        //设置焦点,编辑此文本框
        ui->reg_nickname->setFocus();
        return;
    }

    //将正则规则修改为其他规则,设置为密码正则
    regepx.setPattern(PASSWD_REG);
    //校验密码
    if(!regepx.exactMatch(passwd))
    {
        QMessageBox::warning(this,"警告","密码格式不正确，6-18位大小写字母数字——@#-*组成");
        ui->reg_password->clear();
        ui->reg_password->setFocus();
        return;
    }
    //校验两次输入的密码是否相同
    QString PWD = QString("^%1$").arg(passwd);
    regepx.setPattern(PWD);
    if(!regepx.exactMatch(confirmPwd))
    {
        QMessageBox::warning(this,"警告","两次输入的密码不一致");
        ui->reg_surepassword->clear();
        ui->reg_surepassword->setFocus();
    }

    //校验手机号
    regepx.setPattern(PHONE_REG);
    if(!regepx.exactMatch(phone))
    {
        QMessageBox::warning(this,"警告","phone格式不正确");
        ui->reg_tel->clear();
        ui->reg_tel->setFocus();
    }

    //校验邮箱地址
    regepx.setPattern(EMAIL_REG);
    if(!regepx.exactMatch(email))
    {
        QMessageBox::warning(this,"警告","邮箱地址不正确");
        ui->reg_mail->clear();
        ui->reg_mail->setFocus();
    }
    }

    //用户信息组成，发送到服务器
    //将注册信息组合成json
    QByteArray array = setRegisterJson(username,nickname,m_cn.getStrMd5(passwd),phone,email);
    //连接服务器设置url
    QNetworkRequest request;
    QString url = QString("http://%1:%2/reg").arg(ui->address_server->text()).arg(ui->port_server->text());
    request.setUrl(QUrl(url));
    //设置请求头
    request.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("application/json"));
    request.setHeader(QNetworkRequest::ContentLengthHeader,QVariant(array.size()));
    //发送数据
    QNetworkReply * reply = m_manager->post(request,array);

    //判断请求是否被成功处理
    connect(reply,&QNetworkReply::readyRead,[=]()
    {
        //读取来自服务器的信息，解析其中的信息，并返回状态码提供判断
        QByteArray jsonData = reply->readAll();
        if("002" == m_cn.getCode(jsonData))
        {
            //002代表注册成功，此时清空注册信息，转到登录页并自动填写用户名和密码
            QMessageBox::information(this,"提示","注册成功，请登录");
            ui->reg_usrname->clear();
            ui->reg_nickname->clear();
            ui->reg_password->clear();
            ui->reg_surepassword->clear();
            ui->reg_tel->clear();
            ui->reg_mail->clear();

            ui->stackedWidget->setCurrentIndex(0);
            ui->userName->setText(username);
            ui->password->setText(passwd);
            ui->rember_pwd->setChecked(true);
        }
        else if("003" == m_cn.getCode(jsonData))
        {
            QMessageBox::warning(this,"注册失败","用户名已存在");
        }
        else if("003" == m_cn.getCode(jsonData))
        {
            QMessageBox::warning(this,"注册失败","注册失败");
        }
        // 释放资源
        delete reply;
    });
}

//去注册
void login::on_toregBtn_clicked()
{
    //清除登录页文本框内容
    ui->userName->clear();
    ui->password->clear();
    ui->stackedWidget->setCurrentIndex(1);
}

//设置ip地址和端口号
void login::on_pushButton_4_clicked()
{
    //获取并进行正则校验
    QString ip = ui->address_server->text();
    QString port = ui->port_server->text();

    QRegExp regexp(IP_REG);
    if(!regexp.exactMatch(ip))
    {
        QMessageBox::warning(this,"警告","ip格式错误");
        ui->address_server->clear();
        ui->address_server->setFocus();
        return;
    }

    regexp.setPattern(PORT_REG);
    if(!regexp.exactMatch(port))
    {
        QMessageBox::warning(this,"警告","port格式错误");
        ui->port_server->clear();
        ui->port_server->setFocus();
        return;
    }
    //跳转到登陆界面id=0
    ui->stackedWidget->setCurrentIndex(0);
    //将配置信息写到配置文件中
    m_cn.writeWebInfo(ip,port);
}

//登录
void login::on_loginBtn_clicked()
{
    QString user = ui->userName->text();
    QString pwd = ui->password->text();
    QString address = ui->address_server->text();
    QString port = ui->port_server->text();

    //数据校验
    if(true)
    {
        QRegExp regexp(USER_REG);
        if(!regexp.exactMatch(user))
        {
            QMessageBox::warning(this,"警告","用户名不符合规范");
            ui->userName->clear();
            ui->userName->setFocus();
            return;
        }
        if(!regexp.exactMatch(pwd))
        {
            QMessageBox::warning(this,"警告","密码不符合规范");
            ui->password->clear();
            ui->password->setFocus();
            return;
        }
    }

    //登录信息写入配置文件cfg.json
    //登录信息加密
    m_cn.writeLoginInfo(user,pwd,ui->rember_pwd->isChecked());
    //设置登录信息包
    QByteArray array = setLoginJson(user,m_cn.getStrMd5(pwd));
    //设置登录的url信息
    QNetworkRequest request;
    QString url = QString("http://%1:%2/login").arg(ui->address_server->text()).arg(ui->port_server->text());
    request.setUrl(QUrl(url));
    request.setHeader(QNetworkRequest::ContentTypeHeader,QVariant("application/json"));
    request.setHeader(QNetworkRequest::ContentLengthHeader,QVariant(array.size()));
    //发送post请求
    QNetworkReply * reply = m_manager->post(request,array);
    qDebug()<<" "<< "post url:" << url << "post data: " << array;
    //接收来自服务器返回的消息
    connect(reply,&QNetworkReply::finished,[=]()
    {
        //如果出错了
        if(reply->error() != QNetworkReply::NoError)
        {
            //说明出现错误
            qDebug()<< reply->errorString();
            qDebug()<<"出现错误";
            reply->deleteLater();
            return;
        }
        //
        QByteArray json = reply->readAll();
        QStringList list = getLoginStatus(json);
        if("000" == list.at(0))
        {
            //说明登陆成功，接下来设置单例模式的登录信息，后面需要用
            //
            qDebug()<<"登陆成功";
            LoginInfoInstance *p = LoginInfoInstance::getInstance();
            p->setLoginInfo(user,address,port,list.at(1));
            //隐藏当前窗口，显示主窗口
            this->hide();
            //后面用的自定义的
            m_mainWin->show();
        }
        else
        {
            QMessageBox::warning(this,"警告","用户名与密码不匹配");
        }
        reply->deleteLater();
    });

    //无服务器测试Ui用
    //隐藏当前窗口，显示主窗口
    this->hide();
    //后面用的自定义的
    m_mainWin->show();
}

//读配置文件cgi.json
void login::readCfg()
{
    //调用函数获取用户登录信息的内容
    QString user = m_cn.getCfgValue("login","user");
    QString pwd = m_cn.getCfgValue("login","pwd");
    QString rember = m_cn.getCfgValue("login","remember");
    //对获取到的信息进行解密,记住密码框的设置
    int ret =0;
    if(rember == "yes")
    {
        ui->rember_pwd->setChecked(true);
        //与加密过程相反：从base64变为QByteArray类型，然后对密码解密
        unsigned char encPwd[512] = {0};//存放密码
        int encPwdLen = 0;//密码长度
        QByteArray tmp = QByteArray::fromBase64(pwd.toLocal8Bit());//转换为本地字符集
        ret = DesDec((unsigned char *)tmp.data(),tmp.size(),encPwd,&encPwdLen);
        if(0 != ret)
        {
            qDebug()<<"login_desdec解密出错"<<endl;
            return;
        }
#ifdef _WIN32
        ui->password->setText(QString::fromLocal8Bit( (const char *)encPwd, encPwdLen ));
#else
        ui->password->setText((const char *)encPed);
#endif
    }
    else
    {
        //只需要将密码设置为空即可
        ui->password->setText("");
        ui->rember_pwd->setChecked(false);
    }
    //用户名解密并设置
    if(true)
    {
        //流程和前面密码解密一样
        unsigned char encUsr[512] = {0};
        int encUsrLen = 0;
        QByteArray tmp = QByteArray::fromBase64(user.toLocal8Bit());
        ret = DesDec((unsigned char *)tmp.data(),tmp.size(),encUsr,&encUsrLen);
        if(0 != ret)
        {
            qDebug()<<"login_desdec(user)解密出错"<<endl;
            return;
        }
#ifdef _WIN32
        ui->userName->setText(QString::fromLocal8Bit((const char *)encUsr,encUsrLen));
#else
        ui->userName->setText((unsigned char *)encUsr);
#endif

    }
    //获取ip和port信息并设置
    QString address = m_cn.getCfgValue("web_server","ip");
    ui->address_server->setText(address);
    QString port = m_cn.getCfgValue("web_server","port");
    ui->port_server->setText(port);
}













